#include "include/usb_host.h"
#include "chip/include/sl811hst.h"

#include "core/include/aks_processor.h"
#include "core/include/types.h"
#include "core/include/aks_string.h"

/* ------ debug information ------ */
void showDtInfo(USB_DT *dt)
{
	UART_transmitString(UART_DBG, (BYTE *)"---USB Data Info------\r\n");
	UART_transmitString(UART_DBG, (BYTE *)"---Descriptor Type = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((dt->bDesc)>>4));
		UART_transmitByte(UART_DBG, hex2Ascii((dt->bDesc)>>0));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

	UART_transmitString(UART_DBG, (BYTE *)"---bType = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((dt->bType)>>4));
		UART_transmitByte(UART_DBG, hex2Ascii((dt->bType)>>0));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

	UART_transmitString(UART_DBG, (BYTE *)"---wSize = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((dt->wSize)>>12));
		UART_transmitByte(UART_DBG, hex2Ascii((dt->wSize)>>8 ));
		UART_transmitByte(UART_DBG, hex2Ascii((dt->wSize)>>4 ));
		UART_transmitByte(UART_DBG, hex2Ascii((dt->wSize)>>0 ));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");
}

void showEpDsc(USB_EP *ep)
{
	UART_transmitString(UART_DBG, (BYTE *)"---USB Endpoint Info------\r\n");
	UART_transmitString(UART_DBG, (BYTE *)"---Descriptor Type = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((ep->bDesc)>>4));
		UART_transmitByte(UART_DBG, hex2Ascii((ep->bDesc)>>0));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

	UART_transmitString(UART_DBG, (BYTE *)"---bAdr = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((ep->bAdr)>>4));
		UART_transmitByte(UART_DBG, hex2Ascii((ep->bAdr)>>0));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

	UART_transmitString(UART_DBG, (BYTE *)"---bDirection = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((ep->bDirection)>>4));
		UART_transmitByte(UART_DBG, hex2Ascii((ep->bDirection)>>0));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");


	UART_transmitString(UART_DBG, (BYTE *)"---bType = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((ep->bType)>>4));
		UART_transmitByte(UART_DBG, hex2Ascii((ep->bType)>>0));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

	UART_transmitString(UART_DBG, (BYTE *)"---payload = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((ep->payload)>>12));
		UART_transmitByte(UART_DBG, hex2Ascii((ep->payload)>>8 ));
		UART_transmitByte(UART_DBG, hex2Ascii((ep->payload)>>4 ));
		UART_transmitByte(UART_DBG, hex2Ascii((ep->payload)>>0 ));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

	UART_transmitString(UART_DBG, (BYTE *)"---bInterval = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((ep->bInterval)>>4));
		UART_transmitByte(UART_DBG, hex2Ascii((ep->bInterval)>>0));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

}

void showIfDsc(USB_IF *inf)
{
	UART_transmitString(UART_DBG, (BYTE *)"--USB Interface Info------\r\n");
	UART_transmitString(UART_DBG, (BYTE *)"--Descriptor Type = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((inf->bDesc)>>4));
		UART_transmitByte(UART_DBG, hex2Ascii((inf->bDesc)>>0));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

	UART_transmitString(UART_DBG, (BYTE *)"--bIfIndex = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((inf->bIfIndex)>>4));
		UART_transmitByte(UART_DBG, hex2Ascii((inf->bIfIndex)>>0));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

	UART_transmitString(UART_DBG, (BYTE *)"--bNumEP = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((inf->bNumEP)>>4 ));
		UART_transmitByte(UART_DBG, hex2Ascii((inf->bNumEP)>>0 ));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

	for(BYTE i=0 ; i < inf->bNumEP ; ++i)
	{
		showEpDsc(&(inf->EP[i]));
		showDtInfo(&(inf->DATA[i]));
	}
}

void showCfgDsc(USB_CFG *cfg)
{
	UART_transmitString(UART_DBG, (BYTE *)"-USB Configuration Info------\r\n");
	UART_transmitString(UART_DBG, (BYTE *)"-Descriptor Type = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((cfg->bDesc)>>4));
		UART_transmitByte(UART_DBG, hex2Ascii((cfg->bDesc)>>0));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

	UART_transmitString(UART_DBG, (BYTE *)"-bCfgIndex = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((cfg->bCfgIndex)>>4));
		UART_transmitByte(UART_DBG, hex2Ascii((cfg->bCfgIndex)>>0));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

	UART_transmitString(UART_DBG, (BYTE *)"-bCfgValue = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((cfg->bCfgValue)>>4));
		UART_transmitByte(UART_DBG, hex2Ascii((cfg->bCfgValue)>>0));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");


	UART_transmitString(UART_DBG, (BYTE *)"-bNumIF = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((cfg->bNumIF)>>4 ));
		UART_transmitByte(UART_DBG, hex2Ascii((cfg->bNumIF)>>0 ));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

	for(BYTE i=0 ; i < cfg->bNumIF ; ++i)
	{
		showIfDsc(&(cfg->IF[i]));
	}

}


void showDevDsc(USB_DEV *dev)
{
	UART_transmitString(UART_DBG, (BYTE *)"USB Device Info------\r\n");
	UART_transmitString(UART_DBG, (BYTE *)"bClass = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((dev->bClass)>>4));
		UART_transmitByte(UART_DBG, hex2Ascii((dev->bClass)>>0));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

	UART_transmitString(UART_DBG, (BYTE *)"bSubClass = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((dev->bSubClass)>>4));
		UART_transmitByte(UART_DBG, hex2Ascii((dev->bSubClass)>>0));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

	UART_transmitString(UART_DBG, (BYTE *)"bEP0Payload = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((dev->bEP0Payload)>>4));
		UART_transmitByte(UART_DBG, hex2Ascii((dev->bEP0Payload)>>0));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

	UART_transmitString(UART_DBG, (BYTE *)"adr = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((dev->adr)>>4));
		UART_transmitByte(UART_DBG, hex2Ascii((dev->adr)>>0));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

	UART_transmitString(UART_DBG, (BYTE *)"speed = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((dev->speed)>>4));
		UART_transmitByte(UART_DBG, hex2Ascii((dev->speed)>>0));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

	UART_transmitString(UART_DBG, (BYTE *)"bNumCFG = ");
	{
		UART_transmitByte(UART_DBG, hex2Ascii((dev->bNumCFG)>>4));
		UART_transmitByte(UART_DBG, hex2Ascii((dev->bNumCFG)>>0));
	}
	UART_transmitString(UART_DBG, (BYTE *)"\r\n");

	for(BYTE i=0 ; i < dev->bNumCFG ; ++i)
	{
		showCfgDsc(&(dev->CFG[i]));
	}

}

/* ------ Descriptor Allocators ------ */
#define DSC_SIZE	5
USB_CFG aUsb_Cfgs[DSC_SIZE];	BYTE cfg_use=0;
USB_IF  aUsb_Ifs[DSC_SIZE];	    BYTE if_use =0;
USB_EP  aUsb_Eps[DSC_SIZE];	    BYTE ep_use =0;
USB_DT	aUsb_Dts[DSC_SIZE];	    BYTE dt_use =0;

void USB_allocateCfgDsc(USB_DEV *dev, BYTE num)
{
	if( DSC_SIZE - cfg_use < num )
	{
		return;
	}

	dev->CFG = &(aUsb_Cfgs[cfg_use]);
	cfg_use += num;

	return;
}

void USB_allocateIfDsc(USB_CFG *cfg, BYTE num)
{
	if( DSC_SIZE - if_use < num )
	{
		return;
	}

	cfg->IF = &(aUsb_Ifs[if_use]);
	if_use += num;

	return;
}

void USB_allocateEpDsc(USB_IF *inf, BYTE num)
{
	if( DSC_SIZE - ep_use < num )
	{
		return;
	}

	inf->EP = &(aUsb_Eps[ep_use]);
	ep_use += num;

	return;
}

void USB_allocateDtInf(USB_IF *inf, BYTE num)
{
	if( DSC_SIZE - dt_use < num )
	{
		return;
	}

	inf->DATA = &(aUsb_Dts[dt_use]);
	dt_use += num;

	return;
}



/* ------ USB Descriptor Setting ------ */
void USB_DeviceDescriptor_Processor(BYTE *dsc, WORD len, USB_DEV *dev)
{
	dev->bClass		= dsc[4];
	dev->bSubClass	= dsc[5];
	dev->bEP0Payload= dsc[7];

	dev->bNumCFG	= dsc[17];
	dev->CFG		= 0;
	USB_allocateCfgDsc(dev, dev->bNumCFG);
}


BYTE iCfg;
void USB_ConfigurationDescriptor_Processor(BYTE *dsc, WORD len, USB_DEV *dev)
{
	iCfg = dsc[5] - 1;

	dev->CFG[iCfg].bDesc    = 0x02;
	dev->CFG[iCfg].bCfgIndex= iCfg + 1;
	dev->CFG[iCfg].bCfgValue= dsc[5];

	dev->CFG[iCfg].bNumIF	= dsc[4];
	dev->CFG[iCfg].IF 		= 0;
	USB_allocateIfDsc(&(dev->CFG[iCfg]), dev->CFG[iCfg].bNumIF);
}

BYTE iIf;
BYTE iEp;
BYTE iDt;
void USB_InterfaceDescriptor_Processor(BYTE *dsc, WORD len, USB_DEV *dev)
{
	iIf = dsc[2];

	if(dev->bClass==0)
	{
		dev->bClass = dsc[5];
		dev->bSubClass = dsc[6];
	}

	dev->CFG[iCfg].IF[iIf].bDesc    = 0x04;
	dev->CFG[iCfg].IF[iIf].bIfIndex	= iIf;
	dev->CFG[iCfg].IF[iIf].bNumEP	= dsc[4];
	dev->CFG[iCfg].IF[iIf].EP		= 0;
	iEp = 0;
	iDt = 0;

	USB_allocateEpDsc( &(dev->CFG[iCfg].IF[iIf]), dev->CFG[iCfg].IF[iIf].bNumEP);
	USB_allocateDtInf( &(dev->CFG[iCfg].IF[iIf]), dev->CFG[iCfg].IF[iIf].bNumEP);


}


void USB_EndpointDescriptor_Processor(BYTE *dsc, WORD len, USB_DEV *dev)
{
	dev->CFG[iCfg].IF[iIf].EP[iEp].bDesc	    = 0x05;
	dev->CFG[iCfg].IF[iIf].EP[iEp].bAdr			= dsc[2] & 0x0F;
	dev->CFG[iCfg].IF[iIf].EP[iEp].bDirection	= dsc[2] & 0x80;
	dev->CFG[iCfg].IF[iIf].EP[iEp].bType		= dsc[3];
	dev->CFG[iCfg].IF[iIf].EP[iEp].payload		= (WORD)(dsc[5])<<8 | (WORD)(dsc[4]);
	dev->CFG[iCfg].IF[iIf].EP[iEp].bInterval	= dsc[6];

	iEp++;
}


void USB_HidDescriptor_Processor(BYTE *dsc, WORD len, USB_DEV *dev)
{
	dev->CFG[iCfg].IF[iIf].DATA[iDt].bDesc	= 0x21;
	dev->CFG[iCfg].IF[iIf].DATA[iDt].bType	= dsc[5];
	dev->CFG[iCfg].IF[iIf].DATA[iDt].wSize	= (WORD)(dsc[8])<<8 | (WORD)(dsc[7]);

	iDt++;
}

void USB_dummy(BYTE *dsc, WORD len, USB_DEV *dev)
{
	return;
}

/* Processing Table */
typedef void (*USB_DESC_PROC)(BYTE *, WORD, USB_DEV *);

BYTE USB_DSC_INDEX[] =
{
	0x01,	// Device
	0x02,	// Configuration
	0x04,	// Interface
	0x05,	// Endpoint
	0x21,	// HID
	0x00	// Terminator
};

USB_DESC_PROC USB_DESC_PROC_TABLE[] =
{
	USB_DeviceDescriptor_Processor,
	USB_ConfigurationDescriptor_Processor,
	USB_InterfaceDescriptor_Processor,
	USB_EndpointDescriptor_Processor,
	USB_HidDescriptor_Processor,
	USB_dummy,	//	Terminator
};

BYTE indexFromDscType(BYTE type)
{
	BYTE i;
	for(i=0 ; USB_DSC_INDEX[i] != 0 ; ++i)
	{
		if(USB_DSC_INDEX[i] == type)
		{
			return i;
		}
	}

	return i;
}

/* main Processor */
BYTE USB_DescProcessor(BYTE *dsc, WORD tLen, USB_DEV *dev)
{
	BYTE *tgtDsc = dsc;
	WORD reminder = tLen;

	while( reminder )
	{
		BYTE dscLen = tgtDsc[0];
		BYTE dscType = tgtDsc[1];

		// process Descriptor
		USB_DESC_PROC_TABLE[indexFromDscType(dscType)](tgtDsc, dscLen, dev);

		// next Dscriptor
		reminder -= dscLen;
		tgtDsc += dscLen;
	}

	return 1;
}


/* ------ USB transaction Functions ------ */
BYTE USB_ControlTransport(BYTE speed, BYTE usbAdr, BYTE EPx, USB_REQUEST *setupPacket, BYTE *buf)
{
//	UART_transmitString(UART_DBG, "USB_ControlTransport(): Enter \r\n");

	BYTE result[3] = {0xff, 0xff, 0xff};

	// SETUP transaction
	result[0] = SL811_SETUP_transaction(speed, usbAdr, EPx, (BYTE*)setupPacket, 8);

	// IN Control
	if(setupPacket->bmRequestType & bmDATA_IN)
	{
//		UART_transmitString(UART_DBG, "USB_ControlTransport(): 1 \r\n");
		if(setupPacket->wLength != 0)
		{
//			UART_transmitString(UART_DBG, "USB_ControlTransport(): 1.1 \r\n");
			result[1] = SL811_IN_transaction(speed, usbAdr, EPx, bDATA_1, buf, setupPacket->wLength);
		}
//		UART_transmitString(UART_DBG, "USB_ControlTransport(): 1.2 \r\n");
		result[2] = SL811_OUT_transaction(speed, usbAdr, EPx, bDATA_1, 0, 0);
	}
	// OUT Control
	else
	{
//		UART_transmitString(UART_DBG, "USB_ControlTransport(): 2 \r\n");
		if(setupPacket->wLength != 0)
		{
//			UART_transmitString(UART_DBG, "USB_ControlTransport(): 2.1 \r\n");
			result[1] = SL811_OUT_transaction(speed, usbAdr, EPx, bDATA_1, buf, setupPacket->wLength);
		}
//		UART_transmitString(UART_DBG, "USB_ControlTransport(): 2.2 \r\n");
		result[2] = SL811_IN_transaction(speed, usbAdr, EPx, bDATA_1, 0, 0);
	}

	return result[2];
}


BYTE USB_IN_transaction( BYTE speed, BYTE usbAdr, BYTE EPx, BYTE *buf, WORD len)
{
	return SL811_IN_transaction(speed, usbAdr, EPx, bDATA_0, buf, len);
}


BYTE USB_OUT_transaction(BYTE speed, BYTE usbAdr, BYTE EPx, BYTE *buf, WORD len)
{
	return SL811_OUT_transaction(speed, usbAdr, EPx, bDATA_0, buf, len);

}

/* ------ USB Control Method ------ */
BYTE USB_getDescriptor(DWORD speed, BYTE usbAdr, WORD descType, BYTE *buf, WORD len)
{

	USB_REQUEST request;

	request.bmRequestType	= bmDATA_IN;
	request.bRequest		= GET_DESCRIPTOR;
	request.wValue			= descType;
	request.wIndex			= 0;
	request.wLength			= len;

	return USB_ControlTransport(speed, usbAdr, 0, &request, buf);
}

BYTE USB_setAddress(DWORD speed, WORD usbAdr)
{
	USB_REQUEST request;

	request.bmRequestType	= 0;
	request.bRequest		= SET_ADDRESS;
	request.wValue			= usbAdr;
	request.wIndex			= 0;
	request.wLength			= 0;

	BYTE dat[2];
	dat[0] = SL811_SETUP_transaction(speed, 0, 0, (BYTE*)&request, 8);
	dat[1] = SL811_IN_transaction(   speed, 0, 0, bDATA_1, 0, 0);

	(void)dat;

	return 1;
}

BYTE USB_setConfiguration(DWORD speed, WORD usbAdr, WORD cfgIndex)
{
	USB_REQUEST request;

	request.bmRequestType	= bmDATA_OUT;
	request.bRequest		= SET_CONFIGURATION;
	request.wValue			= cfgIndex;
	request.wIndex			= 0;
	request.wLength			= 0;

	USB_ControlTransport(speed, usbAdr, 0, &request, 0);

	return 1;
}


BYTE uAdr = 0;
BOOL USB_Enumration(USB_DEV *dev)
{
	BYTE buf[1024];
	USB_CONFIGURATION_DESCRIPTOR *pCfgDsc;

	// reset devices
	BYTE speed = SL811_getSpeed();
	if(!speed)
	{
		return FALSE;
	}
	else
	{
		uAdr++;

		dev->speed = speed;
		dev->adr   = uAdr;
	}

	// USB system Reset
//	SL811_USB_Reset();

	UART_transmitString(UART_DBG, (BYTE *)"1. GetDevice Descriptor \r\n");

	// 1. GetDevice Descriptor
	BYTE res = USB_getDescriptor(speed, 0, DEVICE, buf, 18);

	(void)res;

	UART_transmitString(UART_DBG, (BYTE *)"2. Set Address 1? \r\n");
	// 2. Set Address 1?
	USB_setAddress(speed, uAdr);

	UART_transmitString(UART_DBG, (BYTE *)"3. Get Device Descriptor \r\n");
	// 3. Get Device Descriptor
	USB_getDescriptor(speed, uAdr, DEVICE, buf, 18);
	USB_DescProcessor(buf, 18, dev);

	UART_transmitString(UART_DBG, (BYTE *)"4. Get Configuration Descriptor \r\n");
	// 4. Get Configuration Descriptor
	USB_getDescriptor(speed, uAdr, CONFIGURATION, buf, 9);
	pCfgDsc = (USB_CONFIGURATION_DESCRIPTOR *)buf;

	UART_transmitString(UART_DBG, (BYTE *)"5. \r\n");

	USB_getDescriptor(speed, uAdr, CONFIGURATION, buf, pCfgDsc->wTotalLength);
	UART_transmitString(UART_DBG, (BYTE *)"6. \r\n");

	USB_DescProcessor(buf, pCfgDsc->wTotalLength, dev);

	UART_transmitString(UART_DBG, (BYTE *)"7. \r\n");
    return TRUE;
}

BYTE USB_deviceCheck(void)
{
	return SL811HST_deviceCheck();
}

